#include "LockFile.h"
#include <BaseException.h>
#include <cstring>
#include <errno.h>
#include <sstream>

LockFile :: LockFile ()
:fd(-1), m_Nombre("") {
}

LockFile :: LockFile ( const std::string nombre )
:fd(-1), m_Nombre("") {
	this->abrir(nombre);
}

void LockFile::abrir( const std::string nombre )
{
	if(fd >= 0)
		throw BaseException("El archivo ya esta abierto");
	
	this->m_Nombre = nombre;
	this->fl.l_type = F_WRLCK;
	this->fl.l_whence = SEEK_SET;
	this->fl.l_start = 0;
	this->fl.l_len = 0;
	this->fd = open ( this->m_Nombre.c_str(),O_CREAT|O_WRONLY,0777 );
	if(this->fd < 0)
	{
		std::stringstream eMsg;
		eMsg << "Ocurrio un error al abrir el archivo " << nombre;
		eMsg << ". Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str());
	}
}

int LockFile :: tomarLock () {
	this->fl.l_type = F_WRLCK;
	int lockResult = fcntl ( this->fd,F_SETLKW,&(this->fl) );
	if(lockResult < 0)
	{
		std::stringstream eMsg;
		eMsg << "Ocurrio un error al tomar el lock del archivo " << m_Nombre;
		eMsg << "Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str());
	}
	return lockResult;
}

int LockFile :: liberarLock () {
	this->fl.l_type = F_UNLCK;
	int lockResult = fcntl ( this->fd,F_SETLK,&(this->fl) );
	if(lockResult < 0)
	{
		std::stringstream eMsg;
		eMsg << "Ocurrio un error al liberar el lock del archivo " << m_Nombre;
		eMsg << "Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str());
	}
	return lockResult;
}

ssize_t LockFile :: escribir ( const void* buffer,const ssize_t buffsize ) const {
	if(lseek ( this->fd,0,SEEK_END ) < 0)
	{
		std::stringstream eMsg;
		eMsg << "Ocurrio un error al posicionarse en el archivo ";
		eMsg << "Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str());
	}
	ssize_t cantBytesEscritos = write ( this->fd,buffer,buffsize );
	if(cantBytesEscritos < 0)
	{
		std::stringstream eMsg;
		eMsg << "Ocurrio un error al escribir en el archivo " << m_Nombre;
		eMsg << "Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str());
	}
	return cantBytesEscritos;
}

void LockFile::cerrar() {
	if(this->fd > 0)
	{
		close ( this->fd );
		this->fd = -1;
	}
}

void LockFile::eliminar() {
	if(!m_Nombre.empty())
		unlink ( m_Nombre.c_str() );
}

LockFile :: ~LockFile () {
	this->cerrar();
}
